import { ObjectSystemAttribute, FriendOf, ExpandOf } from "../../../../../Decorator/Decorator";
import { LocationProxyComponent } from "../../../../Model/Server/Module/ActorLocation/LocationProxyComponent";
import { AwakeSystem } from "../../../../../Core/Module/EventSystem/IAwakeSystem";
import { DestroySystem } from "../../../../../Core/Module/EventSystem/IDestroySystem";
import { StartSceneConfigCategory } from "../../../../Model/Generate/Server/Config/StartSceneConfig";
import { Entity } from "../../../../../Core/Module/Entity/Entity";
import { ActorMessageSenderComponent } from "../../../../Model/Server/Module/Actor/ActorMessageSenderComponent";
import { ObjectAddRequest, ObjectGetRequest, ObjectGetResponse, ObjectLockRequest, ObjectRemoveRequest, ObjectUnLockRequest } from "../../../../Model/Generate/Share/Message/InnerMessage_S_20001";
import { Exception } from "../../../../../Core/Object/Exception";
import { Log } from "../../../../../Core/Module/Log/Log";

export class LocationProxyComponentHelper {

    public static GetLocationSceneId(key: number): number {
        return StartSceneConfigCategory.Instance.LocationConfig.InstanceId;
    }

}

/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "../../../../../Core/Module/Entity/Entity" {

    interface Entity {
        AddLocation(): Promise<void>;
        RemoveLocation(): Promise<void>;
    }

}

@ExpandOf(Entity)
export class EntityLocationProxyComponentExpand {

    private static async AddLocation(self: Entity): Promise<void> {
        await LocationProxyComponent.Instance.Add(self.Id, self.InstanceId);
    }

    private static async RemoveLocation(self: Entity): Promise<void> {
        await LocationProxyComponent.Instance.Remove(self.Id);
    }

}

/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "../../../../Model/Server/Module/ActorLocation/LocationProxyComponent" {

    interface LocationProxyComponent {
        Add(key: number, instanceId: number): Promise<void>;
        Lock(key: number, instanceId: number, time?: number): Promise<void>;
        UnLock(key: number, oldInstanceId: number, instanceId: number): Promise<void>;
        Remove(key: number): Promise<void>;
        Get(key: number): Promise<number>;
    }

}

@ExpandOf(LocationProxyComponent)
export class LocationProxyComponentSystem {

    private static async Add(self: LocationProxyComponent, key: number, instanceId: number): Promise<void> {
        Log.Info(`location proxy add {key}, {instanceId} {TimeHelper.ServerNow()}`);
        const request = new ObjectAddRequest();
        {
            request.Key = key;
            request.InstanceId = instanceId;
        }
        await ActorMessageSenderComponent.Instance.Call(LocationProxyComponentHelper.GetLocationSceneId(key), request);
    }

    private static async Lock(self: LocationProxyComponent, key: number, instanceId: number, time: number = 60000): Promise<void> {
        Log.Info(`location proxy lock {key}, {instanceId} {TimeHelper.ServerNow()}`);
        const request = new ObjectLockRequest();
        {
            request.Key = key;
            request.InstanceId = instanceId;
            request.Time = time;
        }
        await ActorMessageSenderComponent.Instance.Call(LocationProxyComponentHelper.GetLocationSceneId(key), request);
    }

    private static async UnLock(self: LocationProxyComponent, key: number, oldInstanceId: number, instanceId: number): Promise<void> {
        Log.Info(`location proxy unlock {key}, {instanceId} {TimeHelper.ServerNow()}`);
        const request = new ObjectUnLockRequest();
        {
            request.Key = key;
            request.OldInstanceId = oldInstanceId;
            request.InstanceId = instanceId;
        }
        await ActorMessageSenderComponent.Instance.Call(LocationProxyComponentHelper.GetLocationSceneId(key), request);
    }

    private static async Remove(self: LocationProxyComponent, key: number): Promise<void> {
        Log.Info(`location proxy add {key}, {TimeHelper.ServerNow()}`);
        const request = new ObjectRemoveRequest();
        {
            request.Key = key;
        }
        await ActorMessageSenderComponent.Instance.Call(LocationProxyComponentHelper.GetLocationSceneId(key), request);
    }

    private static async Get(self: LocationProxyComponent, key: number): Promise<number> {
        if (key == 0) {
            throw new Exception(`get location key 0`);
        }

        // location server配置到共享区，一个大战区可以配置N多个location server,这里暂时为1
        const request = new ObjectGetRequest();
        {
            request.Key = key;
        }
        const response = <ObjectGetResponse>await ActorMessageSenderComponent.Instance.Call(LocationProxyComponentHelper.GetLocationSceneId(key), request);
        return response.InstanceId;
    }

}

@FriendOf(LocationProxyComponent)
@ObjectSystemAttribute()
export class LocationProxyComponentAwakeSystem extends AwakeSystem<LocationProxyComponent> {

    Awake(self: LocationProxyComponent): void {
        LocationProxyComponent.Instance = self;
    }

}

@FriendOf(LocationProxyComponent)
@ObjectSystemAttribute()
export class LocationProxyComponentDestroySystem extends DestroySystem<LocationProxyComponent> {

    Destroy(self: LocationProxyComponent): void {
        LocationProxyComponent.Instance = null;
    }

}